/*
 * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *      http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package me.ahoo.wow.command.wait

/**
 * Enumeration of command processing stages.
 *
 * CommandStage defines the various stages a command goes through during processing,
 * from being sent to the bus until all related processing (events, projections, sagas)
 * is complete. Each stage has dependencies on previous stages.
 *
 * @see CommandStageCapable
 */
enum class CommandStage {
    /**
     * Command has been sent to the command bus/queue.
     *
     * This is the initial stage when a command is accepted by the command bus.
     * No processing has occurred yet.
     */
    SENT {
        override val previous: List<CommandStage> = listOf()
    },

    /**
     * Command has been processed by the aggregate root.
     *
     * The aggregate has validated and executed the command, potentially
     * generating domain events.
     */
    PROCESSED {
        override val previous: List<CommandStage> = listOf(SENT)
    },

    /**
     * Aggregate snapshot has been generated.
     *
     * A snapshot of the aggregate state has been created for performance
     * optimization in high-throughput scenarios.
     */
    SNAPSHOT {
        override val previous: List<CommandStage> = listOf(SENT, PROCESSED)
    },

    /**
     * Command-generated events have been projected.
     *
     * All projections (read models) have been updated based on the events
     * generated by command processing.
     */
    PROJECTED {
        override val previous: List<CommandStage> = listOf(SENT, PROCESSED)
        override val shouldWaitFunction: Boolean = true
    },

    /**
     * Command-generated events have been handled by event processors.
     *
     * External event handlers have processed the events generated by the command.
     */
    EVENT_HANDLED {
        override val previous: List<CommandStage> = listOf(SENT, PROCESSED)
        override val shouldWaitFunction: Boolean = true
    },

    /**
     * Command-generated events have been handled by sagas.
     *
     * Saga orchestrators have processed the events and potentially triggered
     * additional commands.
     */
    SAGA_HANDLED {
        override val previous: List<CommandStage> = listOf(SENT, PROCESSED)
        override val shouldWaitFunction: Boolean = true
    };

    /**
     * List of prerequisite stages that must complete before this stage.
     *
     * Defines the stage dependencies and execution order in the command
     * processing pipeline.
     */
    abstract val previous: List<CommandStage>

    /**
     * Whether this stage involves waiting for function execution.
     *
     * Stages like PROJECTED, EVENT_HANDLED, and SAGA_HANDLED require
     * waiting for external function processing to complete.
     */
    open val shouldWaitFunction: Boolean = false

    /**
     * Determines if notification should be sent for this stage.
     *
     * @param processingStage the current processing stage
     * @return true if this stage equals or follows the processing stage
     */
    fun shouldNotify(processingStage: CommandStage): Boolean {
        return this == processingStage || isPrevious(processingStage)
    }

    /**
     * Checks if the given stage is a prerequisite for this stage.
     *
     * @param processingStage the stage to check
     * @return true if the given stage is required before this stage
     */
    fun isPrevious(processingStage: CommandStage): Boolean {
        return processingStage in previous
    }
}

/**
 * Interface for objects that have an associated command stage.
 *
 * Classes implementing this interface can report their current command
 * processing stage, useful for tracking progress and waiting strategies.
 *
 * @see CommandStage
 */
interface CommandStageCapable {
    val stage: CommandStage
}
